home *** CD-ROM | disk | FTP | other *** search
- /*
- Libraries for dealing with pictures within PICTs
- copyright © 1992 Apple Computer, Inc.
- All rights reserved.
-
-
- Routines in this library:
- PictureToPICT - creates a PICT with an embedded picture shape
- DrawPictureOrProxy - renders a PICT created with the above call
- */
- #include <Types.h>
- #include <Quickdraw.h>
- #include <ToolUtils.h>
- #include <Memory.h>
-
- #include "graphics routines.h"
- #include "graphics toolbox.h"
- #include "math routines.h"
- #include "storage library.h"
- #include "offscreen library.h"
- #include "qd library.h"
-
- //-----------------------------------------------------------------------------
- // INTERNAL TYPEDEFS AND DEFINES
- //-----------------------------------------------------------------------------
-
- // IDs for the PicComments
- #define shapeSignature 'shpe'
- #define shapeBegin 500
- #define shapeEnd 501
-
- // typedefs for the new PicComments
- typedef struct
- {
- OSType signature; // always == shapeSignature
- short kind; // always == shapeBegin
- Rect bounds; // bounds of shape @ 72 dpi
- char data[1]; // flattened shape data, total size of record determines
- // size
- } ShapeBeginRecord, *ShapeBeginPtr, **ShapeBeginHdl;
-
- typedef struct
- {
- OSType signature; // always == shapeSignature
- short kind; // always == shapeEnd
- } ShapeEndRecord, *ShapeEndPtr, **ShapeEndHdl;
-
- // calling conventions for a comment bottleneck
- typedef pascal void (*CommentProcPtr)(short kind, short dataSize, Handle dataHandle);
-
- //-----------------------------------------------------------------------------
- // GLOBAL VARIABLES
- //-----------------------------------------------------------------------------
- short gAmRendering; // are we handing rendering through GX?
- short gWereProcsInstalled; // were there already procs installed, or did we add them?
-
- Rect gPicFrame; // original size of picture
- Rect gDestRect; // new size of picture
- CQDProcs gSavedProcs; // if there were procs installed, we save them here
-
- //-----------------------------------------------------------------------------
- // INTERNAL ROUTINES
- //-----------------------------------------------------------------------------
- pascal void NilTextBottleneck(short count, Ptr textAddr, Point numer, Point denom)
- /*
- This bottleneck just NOPs out anything passing through it.
- */
- {
- #pragma unused (count,textAddr,numer,denom)
- return;
-
- } // NilTextBottleneck
- /* ------------------------------------------------------------------------ */
-
- pascal void NilLineBottleneck(Point newPt)
- /*
- This bottleneck just NOPs out anything passing through it.
- */
- {
- #pragma unused (newPt)
- return;
-
- } // NilLineBottleneck
-
- /* ------------------------------------------------------------------------ */
-
- pascal void NilRectBottleneck(GrafVerb verb, Rect *r)
- /*
- This bottleneck just NOPs out anything passing through it.
- */
- {
- #pragma unused (verb,r)
- return;
-
- } // NilRectBottleneck
-
- /* ------------------------------------------------------------------------ */
-
- pascal void NilRRectBottleneck(GrafVerb verb,const Rect *r,short ovalWidth,short ovalHeight)
- /*
- This bottleneck just NOPs out anything passing through it.
- */
- {
- #pragma unused (verb,r,ovalWidth,ovalHeight)
-
- return;
-
- } // NilRRectBottleneck
-
- /* ------------------------------------------------------------------------ */
-
- pascal void NilPolyBottleneck(GrafVerb verb,PolyHandle poly)
- /*
- This bottleneck just NOPs out anything passing through it.
- */
- {
- #pragma unused (verb,poly)
- return;
-
- } // NilPolyBottleneck
-
- /* ------------------------------------------------------------------------ */
-
- pascal void NilBitsBottleneck(const BitMap *srcBits,const Rect *srcRect,const Rect *dstRect, short mode,RgnHandle maskRgn)
- /*
- This bottleneck just NOPs out anything passing through it.
- */
- {
- #pragma unused (srcBits,srcRect,dstRect,mode,maskRgn);
- return;
-
- } // NilBitsBottleneck
-
- /* ------------------------------------------------------------------------ */
-
- pascal void RenderComment(short kind, short dataSize, Handle dataHandle)
- /*
- This bottleneck routine gets called to detect the shapeBegin/shapeEnd pairs.
- Within these pairs, all other bottlenecks will be NOPed out, and we'll
- draw QuickDraw GX data instead.
- */
- {
- GrafPtr curPort;
- CQDProcsPtr grafProcs;
- gxShape theShape;
-
- GetPort(&curPort);
-
- switch (kind)
- {
- case shapeBegin:
- // when we see the start comment, stop all QuickDraw drawing via the bottlenecks
- grafProcs = (CQDProcsPtr) qd.thePort->grafProcs;
- #ifndef __powerc
- grafProcs->textProc = (Ptr) NilTextBottleneck;
- grafProcs->lineProc = (Ptr) NilLineBottleneck;
- grafProcs->rectProc = (Ptr) NilRectBottleneck;
- grafProcs->rRectProc = (Ptr) NilRRectBottleneck;
- grafProcs->ovalProc = (Ptr) NilRectBottleneck;
- grafProcs->arcProc = (Ptr) NilRRectBottleneck;
- grafProcs->polyProc = (Ptr) NilPolyBottleneck;
- grafProcs->rgnProc = (Ptr) NilPolyBottleneck;
- grafProcs->bitsProc = (Ptr) NilBitsBottleneck;
- #else
- grafProcs->textProc = NewQDTextProc( (ProcPtr) NilTextBottleneck );
- grafProcs->lineProc = NewQDLineProc( (ProcPtr) NilLineBottleneck );
- grafProcs->rectProc = NewQDRectProc( (ProcPtr) NilRectBottleneck );
- grafProcs->rRectProc = NewQDRRectProc( (ProcPtr) NilRRectBottleneck );
- grafProcs->ovalProc = NewQDOvalProc( (ProcPtr) NilRectBottleneck );
- grafProcs->arcProc = NewQDArcProc( (ProcPtr) NilRRectBottleneck );
- grafProcs->polyProc = NewQDPolyProc( (ProcPtr) NilPolyBottleneck );
- grafProcs->rgnProc = NewQDRgnProc( (ProcPtr) NilPolyBottleneck );
- grafProcs->bitsProc = NewQDBitsProc( (ProcPtr) NilBitsBottleneck );
- #endif
-
- // We now are in charge of this grafPort
- gAmRendering = true;
-
- // remove the header from the shape data
- Munger(dataHandle, 0, nil, sizeof(OSType) + sizeof(short) + sizeof(Rect), (Ptr)2, 0);
-
-
- // place the shape within the current window
- {
- gxViewPort windowViewPort = GXGetWindowViewPort(FrontWindow());
-
- theShape = HandleToShape(dataHandle, 1, &windowViewPort );
- }
-
- // move the shape into the correct position of the window
- {
- gxShape clipShape;
- gxRectangle clipRect;
-
- GXScaleTransform(GXGetShapeTransform(theShape),
- FixRatio(gDestRect.right - gDestRect.left, gPicFrame.right - gPicFrame.left),
- FixRatio(gDestRect.bottom - gDestRect.top, gPicFrame.bottom - gPicFrame.top),
- 0, 0);
- GXMoveShapeTo(theShape, ff(gDestRect.left), ff(gDestRect.top) );
-
- // clip against the draw area
- clipRect.left = ff(gDestRect.left);
- clipRect.top = ff(gDestRect.top);
- clipRect.right = ff(gDestRect.right);
- clipRect.bottom = ff(gDestRect.bottom);
- clipShape = GXNewRectangle(&clipRect);
- GXSetShapeClip(theShape, clipShape);
- GXDisposeShape(clipShape);
- }
-
- // finally, draw the data and get rid of it once done
- GXDrawShape(theShape);
- GXDisposeShape(theShape);
-
- break;
-
- case shapeEnd:
-
- // when we see the end comment, we restore all of the bottlenecks
- grafProcs = (CQDProcsPtr) qd.thePort->grafProcs;
- grafProcs->textProc = gSavedProcs.textProc;
- grafProcs->lineProc = gSavedProcs.lineProc;
- grafProcs->rectProc = gSavedProcs.rectProc;
- grafProcs->rRectProc = gSavedProcs.rRectProc;
- grafProcs->ovalProc = gSavedProcs.ovalProc;
- grafProcs->arcProc = gSavedProcs.arcProc;
- grafProcs->polyProc = gSavedProcs.polyProc;
- grafProcs->rgnProc = gSavedProcs.rgnProc;
- grafProcs->bitsProc = gSavedProcs.bitsProc;
-
- #ifdef __powerc
- DisposeRoutineDescriptor( grafProcs->textProc );
- DisposeRoutineDescriptor( grafProcs->lineProc );
- DisposeRoutineDescriptor( grafProcs->rectProc );
- DisposeRoutineDescriptor( grafProcs->rRectProc );
- DisposeRoutineDescriptor( grafProcs->ovalProc );
- DisposeRoutineDescriptor( grafProcs->arcProc );
- DisposeRoutineDescriptor( grafProcs->polyProc );
- DisposeRoutineDescriptor( grafProcs->rgnProc );
- DisposeRoutineDescriptor( grafProcs->bitsProc );
- #endif
- // we're detached from the bottlenecks now
- gAmRendering = false;
- break;
-
- default:
- // if we aren't rendering GX data yet, let the comment proc go through
- if ( !(gAmRendering) )
- {
- if (gWereProcsInstalled)
- {
- // use the previously installed comment
- grafProcs = (CQDProcsPtr) qd.thePort->grafProcs;
-
- (* (CommentProcPtr) (gSavedProcs.commentProc)) (kind, dataSize, dataHandle);
- }
- else
- {
- // use the ROM comment proc - not that it normally does anything
- StdComment(kind, dataSize, dataHandle);
- }
- }
- break;
-
- } // switch (kind)
-
- } // RenderComment
-
- //-----------------------------------------------------------------------------
- // EXTERNAL ROUTINES
- //-----------------------------------------------------------------------------
- void DrawPictureOrProxy(PicHandle hPicture, Rect *dstRect)
- /*
- This library routine demonstrates how to render a picture, such that GX proxies
- (as generated through PictureToPICT) are rendered using GX rather than QuickDraw.
-
- This routine works by installing QuickDraw bottlenecks that interpret the data
- in the PicComments to determine when GX data is to be used.
-
- This call assumes that a valid QuickDraw window exists, and that it has a valid
- window viewPort - created by calling NewWindowViewPort.
- */
- {
- #ifdef __powerc
- QDCommentUPP rendercomment = NewQDCommentProc((ProcPtr) RenderComment );
- #endif
-
- // so far, no GX data
- gAmRendering = false;
-
- // remember where picture is being drawn (offset by the origin)
- gPicFrame = (**hPicture).picFrame;
- gDestRect = *dstRect;
- OffsetRect(&gDestRect, -qd.thePort->portRect.left, -qd.thePort->portRect.top);
-
- // are there existing procs?
- if (qd.thePort->grafProcs != nil)
- {
- // remember that there were orginally bottlenecks
- gWereProcsInstalled = true;
-
- // save the old procs away
- gSavedProcs = *((CQDProcs*)qd.thePort->grafProcs);
-
- // install our StdComment proc
- #ifndef __powerc
- qd.thePort->grafProcs->commentProc = (Ptr) RenderComment;
- #else
- qd.thePort->grafProcs->commentProc = rendercomment;
- #endif
- }
- else
- {
- // no existing procs, so install new bottlenecks
- gWereProcsInstalled = false;
-
- // install the standard procs
- if (qd.thePort->portBits.rowBytes & 0x80000000)
- SetStdCProcs(&gSavedProcs);
- else
- SetStdProcs((QDProcs*) &gSavedProcs);
-
- // and a custom comment proc
- #ifndef __powerc
- gSavedProcs.commentProc = (Ptr) RenderComment;
- #else
- gSavedProcs.commentProc = rendercomment;
- #endif
-
- // stick the procs into the port
- qd.thePort->grafProcs = (QDProcs*) &gSavedProcs;
- }
-
- // render the data
- DrawPicture(hPicture, dstRect);
-
- if (gWereProcsInstalled)
- {
-
- // if there were originally bottlenecks in the port, replace them
- if (qd.thePort->portBits.rowBytes & 0x80000000)
- *(((CGrafPtr)qd.thePort)->grafProcs) = gSavedProcs;
- else
- *(qd.thePort->grafProcs) = * ((QDProcs*) &gSavedProcs);
- }
- else
- {
-
- // deinstall our bottlenecks
- qd.thePort->grafProcs = nil;
- }
-
- #ifdef __powerc
- DisposeRoutineDescriptor( rendercomment );
- #endif
-
- } // DrawPictureOrProxy
-
- //-----------------------------------------------------------------------------
- PicHandle PictureToPICT(gxShape theShape, Boolean simpleProxy)
- /*
- This library routine turns a QuickDraw GX™ shape into a QuickDraw PICT.
- It does this using three steps:
- 1) it emits a QuickDraw PicComment, and places the flattened GX data into
- the comment.
- 2) it converts the GX picture into a QuickDraw proxy. It uses a rectangle
- with an 'X' through it if simpleProxy is true. Otherwise, it uses a 1 bit
- bitmap rendition of the shape.
- 3) it emits a QuickDraw PictComment, marking the end of the QuickDraw proxy.
-
- The resulting PICT can be cut & pasted, or saved into a PICT file. On a system
- with QuickDraw GX™ installed, the GX data will be used when printing.
- When printing on other systems, the QuickDraw proxy will be used.
-
- The proxy is always used for display from within non-GX applications.
- */
- {
- gxGraphicsError gxErr = noErr;
- PicHandle thePicture;
- Rect picRect;
- ShapeBeginRecord theBegin;
- Handle hBegin;
- ShapeEndHdl hEnd;
- gxRectangle shapeBounds;
-
- // get the location of the shape
- GXGetShapeDeviceBounds(theShape, 0, 0, &shapeBounds);
- picRect.left = FixedToInt(shapeBounds.left);
- picRect.top = FixedToInt(shapeBounds.top);
- picRect.right = FixedToInt(shapeBounds.right);
- picRect.bottom = FixedToInt(shapeBounds.bottom);
- GlobalToLocal((Point*) &picRect.top);
- GlobalToLocal((Point*) &picRect.bottom);
-
- thePicture = OpenPicture(&picRect);
- if (thePicture != nil)
- {
- // use a standard clipping and pen mode
- ClipRect(&picRect);
- PenNormal();
-
- // flatten our shape out into a handle
- hBegin = ShapeToHandle(theShape);
- if (hBegin != nil)
- {
- // add the comment to the begining of the handle
- theBegin.signature = shapeSignature;
- theBegin.kind = shapeBegin;
- theBegin.bounds = picRect;
- Munger(hBegin, 0, nil, 0, &theBegin, sizeof(OSType) + sizeof(short) + sizeof(Rect) );
- gxErr = MemError();
-
- // store the shape/handle into the picture
- PicComment(shapeBegin, GetHandleSize(hBegin), hBegin);
- DisposHandle(hBegin);
-
- }
- else
- gxErr = MemError();
-
- if (gxErr == noErr)
- {
- if (simpleProxy)
- {
- // our proxy is just a framed rect with an X through it
- FrameRect(&picRect);
- MoveTo(picRect.left, picRect.top);
- LineTo(picRect.right, picRect.bottom);
- MoveTo(picRect.right, picRect.top);
- LineTo(picRect.left, picRect.bottom);
- }
- else
- {
- // our proxy is a bitmap of the GX object
- gxBitmap theBits;
- gxShape theBitmap;
-
- theBits.width = picRect.right - picRect.left;
- theBits.height = picRect.bottom - picRect.top;
- theBits.pixelSize = 1;
- theBits.rowBytes = ((theBits.width + 31) >> 5) << 2;
- theBits.image = NewPtrClear(theBits.height * theBits.rowBytes);
- theBits.space = gxIndexedSpace;
- theBits.set = nil;
- theBits.profile = nil;
-
- gxErr = MemError();
- if (gxErr == noErr)
- {
- theBitmap = GXNewBitmap(&theBits, nil);
- GXMoveTransformTo(GXGetShapeTransform(theBitmap), -shapeBounds.left, -shapeBounds.top);
- GXGetGraphicsError(&gxErr);
- if (gxErr == noErr)
- {
- BitMap qdBits;
-
- // put the shape into the bitmap
- CopyToBitmaps(theBitmap, theShape);
- ConvertToQDBitmap(&theBits, &qdBits);
- GXGetGraphicsError(&gxErr);
-
- // now done with the bitmap
- GXDisposeShape(theBitmap);
-
- // CopyBits it into the picture
- CopyBits(&qdBits, &qd.thePort->portBits, &qdBits.bounds, &picRect, srcOr, nil);
-
- }
-
- // and done with the image
- DisposePtr(theBits.image);
- }
- }
-
- // mark the end of our shape's proxy
- hEnd = (ShapeEndHdl) NewHandle(sizeof(ShapeEndRecord));
- if (hEnd != nil)
- {
- (**hEnd).signature = shapeSignature;
- (**hEnd).kind = shapeEnd;
- PicComment(shapeEnd, GetHandleSize((Handle) hEnd), (Handle) hEnd);
- DisposHandle((Handle) hEnd);
- }
- else
- gxErr = MemError();
- }
-
- ClosePicture();
- }
- else
- gxErr = MemError();
-
- // if we had a problem, return a nil picture
- if ( ( gxErr != noErr ) && thePicture )
- {
- KillPicture(thePicture);
- thePicture = nil;
- }
-
- return(thePicture);
-
- } // PictureToPICT
-